Repository navigation
OPFS VFSs: add getRoot and prefix options (upstream #380) - #95
darshanp40 wants to merge 5 commits into
Conversation
AccessHandlePoolVFS, OPFSCoopSyncVFS and OPFSWriteAheadVFS can keep their files in a Storage Bucket instead of the default bucket of the origin private file system. Lock and BroadcastChannel names derived from a file name get the bucket name as a prefix, so a file of the same name in another bucket shares none of them. Without the option nothing changes.
rkistner
left a comment
There was a problem hiding this comment.
Storage buckets are still experimental in Chrome, with no support in other browsers, and not much movement over the last two years. Your MDN link gives a 404.
Given your description, this sounds like a Chrome bug more than anything else, and should probably be fixed there instead. It's also not something most users will run into, since the option to clear the data is not even accessible in DevTools. Is there perhaps another workaround, or a way to detect this condition and produce a better error, perhaps asking the user to reload the page?
|
Thanks for the review, @rkistner. Link. You're right, MDN has no page for Storage Buckets. I've replaced the link with the spec, https://wicg.github.io/storage-buckets/, in the description and in the code comment. Browser support. The API is shipped and on by default in Chromium since version 122, in Chrome, Edge, Opera and Chrome for Android (Chrome's announcement). caniuse shows it supported for 72.15% of global browser usage, with no Firefox or Safari support, and MDN's compatibility data lists it as experimental and standards-track. That is why this is opt-in and feature-detected: without the option nothing changes, in any browser. The defect is in Chromium's file system code, and the API exists in the same Chromium-based browsers. A Chrome bug. Agreed, the cause is in Chromium and it should be fixed there. We have a report for Chromium ready with these steps, and I'll link it here once it's filed. A fix there will take a while to reach installed browsers, though, and until then an app can't avoid it from the outside. How users run into it. The DevTools button doesn't trigger it, as you say: it keeps the storage bucket. The everyday ways of clearing a site's data do. Measured today on Chrome 154.0.8037.98, with a tab of the site open while the data is cleared:
I've added the steps for all three to the description. We see it in production on Chrome and Edge, on macOS and Windows. It affects a few users a month, but for each of them the app can't open its database until they restart the browser. Reloading doesn't help. Once it happens, reloading the page and opening new tabs fail the same way. It ends only when the browser restarts, or after 10 minutes in which no site in that browser profile uses OPFS. Every retry starts those 10 minutes again. So a better error would have to ask the user to restart the browser, not to reload. Detection. It can be detected: listing the root directory fails with this Other workarounds we tried.
The named bucket is the only approach that avoided both effects in every case we tried. Suggestion. Keep this as an opt-in option, so apps that don't set it see no change. If you'd rather the library didn't refer to Storage Buckets at all, the VFS could instead take a function that returns its root directory, plus a prefix for its lock names, and the bucket would be entirely the app's choice. Separately, I can open a PR for the detection with a specific error, if that's useful to you. |
|
I agree that we shouldn't ship workarounds for things that should be fixed in Chrome (but I'm not sure if this continuing to work for named buckets is intentional, these not being affected when site data is cleared sounds like named buckets just aren't cleaned up properly). That said, given that OPFS writeahead only works on Chrome too (and uses flags that haven't made it into the standard yet), I'm not opposed to adding support for storage buckets for the other isolation features they bring. However, instead of this package probing |
|
@darshanp40 Thanks for the extra details. I missed in your original report that the user can easily go to site settings to delete the data, without manually navigating to @simolus3 I like your suggestion of accepting an With that we'd still have this broken for users not using storage buckets, but at least there would be a workaround available until the issue is fixed in Chrome. |
Review feedback: the library should not probe navigator.storageBuckets. AccessHandlePoolVFS, OPFSCoopSyncVFS and OPFSWriteAheadVFS now take getRoot, a function returning the directory they keep their files in, and OPFSCoopSyncVFS and OPFSWriteAheadVFS take lockPrefix, put in front of the Web Lock and BroadcastChannel names they derive from file names. A Storage Bucket, a directory below the root or any other directory handle can be passed in by the app. Without the options nothing changes. The tests use a directory below the root, so they run in every browser the suite runs in.
…limits OPFSWriteAheadVFS now puts lockPrefix in front of its .session-* directory locks too, as OPFSCoopSyncVFS does for its .ahp-* locks. The lockPrefix documentation says to use one prefix per root and names the case it cannot cover: a file under the default root whose name starts with the prefix. The AccessHandlePoolVFS documentation says it requests the root once. The root test worker reports worker errors instead of waiting for an answer.
|
Thanks, both. I've reworked the PR along those lines. The API. The VFSs no longer know about Storage Buckets. Tests. The suite now uses a directory below the default root instead of a bucket, so it runs in every browser the suite runs in: the files land only under that root, same-named files under the two roots keep their own data and never wait on each other, and a On named buckets not being cleaned up (@simolus3). I checked, since it would matter. They are deleted with the rest of the site's data. Measured on Chrome 154.0.8037.98 with a bucket
The same with no tab open during the deletion: the bucket and its file are gone. In the default bucket the listing through the old handle also fails at once. The create through it is where the two differ: it fails after about 6 seconds, with the same @rkistner, agreed that apps on the default root stay exposed until Chromium fixes this. The option gives them a way out that did not exist before, and the description now leads with the generic use of the two options, with the Chromium material at the end. Chromium report. Still to be filed on our side; I'll link it here when it is. |
|
Hi @rkistner and @simolus3, a gentle follow-up on this one. The PR now follows the direction you suggested on 7 October: the VFSs take a Could you let me know:
I am happy to make any changes needed. Thank you for your time. |
|
Thanks for the reminder, I have approved the CI run. I'm happy with the API changes here, they're pretty simple and should work for other use-cases as well. Given that this is also relevant for other (non-PowerSync) |
|
Thanks @simolus3, for approving the run and for the review. I've opened the same change against the original project as rhashimoto#380. All the files it touches are identical there, and it applies to the current I'll keep this PR open until Roy has had a look. If he accepts it there, this one can be closed and the change will reach this fork with the next merge from upstream. If he would rather not take it, I'm happy to land it here as you suggested. |
The change was merged into rhashimoto/wa-sqlite as rhashimoto#380, with the option renamed from lockPrefix to prefix and the options read from this.options. This branch now carries that exact change on top of master, plus a changeset.
|
I'll open a PR to merge from upstream, which now includes your changes. Thanks! |
Summary
This brings rhashimoto#380, merged upstream on 23 October, into PowerSync's fork. It is the upstream change exactly, plus a changeset. As discussed here earlier, the change went upstream first so that this fork does not drift from it.
getRootoption toAccessHandlePoolVFS,OPFSCoopSyncVFSandOPFSWriteAheadVFS: a function that returns the directory the VFS keeps its files in. The default is() => navigator.storage.getDirectory(), which is what the VFSs use today.prefixoption toOPFSCoopSyncVFSandOPFSWriteAheadVFS. It is put in front of every Web Lock and BroadcastChannel name the VFS derives from a file name, so that a file of the same name under another root does not share them.this.options, with the defaults there.Why PowerSync needs it
powersync-ja/powersync-js#1142 uses these options to offer a
storageBucketoption in@powersync/web. It keeps the database in a named Storage Bucket, which avoids a Chromium defect in the default bucket: after a user deletes a site's data, a handle from before the deletion can make every OPFS call of the site fail until the browser restarts, and can delete files a newer tab stored. The Chromium bug is https://issues.chromium.org/issues/575150688. The earlier comments on this PR have the measurements and the steps to reproduce.How this branch was made
6b59b2310.masterof this fork, so it applies without conflicts..changeset/root-options.mdmarks it as a minor change of@journeyapps/wa-sqlite.If you would rather take it through your next sync with upstream, this PR can simply be closed.
Tests
test/vfs_root.js, run for each of the three VFSs with a directory below the default root asgetRootand its name asprefix: the files land only under that directory, a file of the same name under the default root keeps its own data, a transaction on one never blocks the other, and agetRootthat fails makes the open fail with its error.vfs_xAccess,vfs_xOpen,vfs_xClose,vfs_xReadandvfs_xWritesuites also run under the custom root.yarn teston this branch, Chrome 155.0.8059.41: 15 files, 6,287 tests passed, 0 failed.